/*******************************************************************************
  MPLAB Harmony Application Source File
  
  Company:
    Microchip Technology Inc.
  
  File Name:
    app4.c

  Summary:
    This file contains the source code for the MPLAB Harmony application.

  Description:
    This file contains the source code for the MPLAB Harmony application.  It 
    implements the logic of the application's state machine and it may call 
    API routines of other MPLAB Harmony modules in the system, such as drivers,
    system services, and middlew`are.  However, it does not call any of the
    system interfaces (such as the "Initialize" and "Tasks" functions) of any of
    the modules in the system or make any assumptions about when those functions
    are called.  That is the responsibility of the configuration-specific system
    files.
 *******************************************************************************/

// DOM-IGNORE-BEGIN
/*******************************************************************************
Copyright (c) 2013-2014 released Microchip Technology Inc.  All rights reserved.

Microchip licenses to you the right to use, modify, copy and distribute
Software only when embedded on a Microchip microcontroller or digital signal
controller that is integrated into your product or third party product
(pursuant to the sublicense terms in the accompanying license agreement).

You should refer to the license agreement accompanying this Software for
additional information regarding your rights and obligations.

SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER
CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR
OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR
CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF
SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
 *******************************************************************************/
// DOM-IGNORE-END


// *****************************************************************************
// *****************************************************************************
// Section: Included Files 
// *****************************************************************************
// *****************************************************************************

#include "app4.h"
#include "pcf8575.h"
#include "ad5620.h"
#include "user_config.h"

// *****************************************************************************
// *****************************************************************************
// Section: Global Data Definitions
// *****************************************************************************
// *****************************************************************************

// *****************************************************************************
/* Application Data

  Summary:
    Holds application data

  Description:
    This structure holds the application's data.

  Remarks:
    This structure should be initialized by the APP_Initialize function.
    
    Application strings and buffers are be defined outside this structure.
*/

APP4_DATA app4Data;


OS_SEM   freq_ctrl_sem; //远程控制AO输出信号量。 
uint16_t set_freq_value; //需要调整到的频率值。 

uint32_t timer_value = 0;
uint32_t moment_value = 0;
uint32_t motor_idle_count = 0;
uint32_t motor_test_count = 0;

uint16_t motor_model= 0;	//测试输出模式
uint16_t motor_test_nb = 1;	//测试次数
uint16_t motor_timer1 = 1000;	//时间点1
uint16_t motor_timer2 = 2000;
uint16_t motor_timer3 = 3000;
uint16_t motor_timer4 = 4000;
uint16_t motor_timer5 = 5000;
uint16_t motor_moment1 = 3000;	//力矩1
uint16_t motor_moment2 = 2000;
uint16_t motor_moment3 = 3000;
uint16_t motor_moment4 = 4000;
uint16_t motor_moment5 = 5000;


// *****************************************************************************
// *****************************************************************************
// Section: Application Callback Functions
// *****************************************************************************
// *****************************************************************************

/* TODO:  Add any necessary callback funtions.
*/

// *****************************************************************************
// *****************************************************************************
// Section: Application Local Functions
// *****************************************************************************
// *****************************************************************************

/* TODO:  Add any necessary local functions.
*/

void load_motor_cfg_tbl(void)
{
	motor_model = cfg_tbl[0]; //测试输出模式
	motor_test_nb = cfg_tbl[1]; //测试次数
	motor_timer1 = cfg_tbl[2]; //时间点1
	motor_timer2 = cfg_tbl[3];
	motor_timer3 = cfg_tbl[4];
	motor_timer4 = cfg_tbl[5];
	motor_timer5 = cfg_tbl[6];
	motor_moment1 = cfg_tbl[7]; //力矩1
	motor_moment2 = cfg_tbl[8];
	motor_moment3 = cfg_tbl[9];
	motor_moment4 = cfg_tbl[10];
	motor_moment5 = cfg_tbl[11];
	return;
}

void load_motor_def_para(void){

	cfg_tbl[0] = 0;	//测试输出模式
	cfg_tbl[1]= 1;	//测试次数
	cfg_tbl[2] = 1000;	//时间点1
	cfg_tbl[3] = 2000;
	cfg_tbl[4] = 3000;
	cfg_tbl[5] = 4000;
	cfg_tbl[6] = 5000;
	cfg_tbl[7] = 3000;	//力矩1
	cfg_tbl[8] = 2000;
	cfg_tbl[9] = 3000;
	cfg_tbl[10] = 4000;
	cfg_tbl[11] = 5000;
	return;
}
/*
 * ===  FUNCTION  ======================================================================
 *         Name:  ad5620_cs_hi
 *  Description:
 * =====================================================================================
 */
void ad5620_cs_hi(void){
	PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_D, PORTS_BIT_POS_2);
	return ;
}		/* -----  end of function ad5620_cs_hi  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  ad5620_cs_lo
 *  Description:
 * =====================================================================================
 */
void ad5620_cs_lo(void){
	PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_D, PORTS_BIT_POS_2);
	return ;
}		/* -----  end of function ad5620_cs_lo  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  ad5620_do_hi
 *  Description:
 * =====================================================================================
 */
void ad5620_do_hi(void){
	PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_D, PORTS_BIT_POS_3);
	return ;
}		/* -----  end of function ad5620_do_hi  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  ad5620_do_lo
 *  Description:
 * =====================================================================================
 */
void ad5620_do_lo(void){
	PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_D, PORTS_BIT_POS_3);
	return ;
}		/* -----  end of function ad5620_do_lo  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  ad5620_ck_hi
 *  Description:
 * =====================================================================================
 */
void ad5620_ck_hi(void){
	PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_D, PORTS_BIT_POS_1);
	return ;
}		/* -----  end of function ad5620_ck_hi  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  ad5620_ck_lo
 *  Description:
 * =====================================================================================
 */
void ad5620_ck_lo(void){
	PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_D, PORTS_BIT_POS_1);
	return ;
}		/* -----  end of function ad5620_ck_lo  ----- */


/*
 * ===  FUNCTION  ======================================================================
 *         Name:  mcp4161_cs_hi
 *  Description:
 * =====================================================================================
 */
void mcp4161_cs_hi(void){
	PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_D, PORTS_BIT_POS_4);
	return ;
}		/* -----  end of function mcp4161_cs_hi  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  mcp4161_cs_lo
 *  Description:
 * =====================================================================================
 */
void mcp4161_cs_lo(void){
	PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_D, PORTS_BIT_POS_4);
	return ;
}		/* -----  end of function mcp4161_cs_lo  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  mcp4161_do_hi
 *  Description:
 * =====================================================================================
 */
void mcp4161_do_hi(void){

	return ;
}		/* -----  end of function mcp4161_do_hi  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  mcp4161_do_lo
 *  Description:
 * =====================================================================================
 */
void mcp4161_do_lo(void){

	return ;
}		/* -----  end of function mcp4161_do_lo  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  mcp4161_ck_hi
 *  Description:
 * =====================================================================================
 */
void mcp4161_ck_hi(void){

	return ;
}		/* -----  end of function mcp4161_ck_hi  ----- */

/*
 * ===  FUNCTION  ======================================================================
 *         Name:  mcp4161_ck_lo
 *  Description:
 * =====================================================================================
 */
void mcp4161_ck_lo(void){

	return ;
}		/* -----  end of function mcp4161_ck_lo  ----- */


// *****************************************************************************
// *****************************************************************************
// Section: Application Initialization and State Machine Functions
// *****************************************************************************
// *****************************************************************************

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  set_increase_freq
 *  Description:  增加频率
 * =====================================================================================
 */
void set_increase_freq(uint16_t freq_value){

	uint16_t i = 1;
	uint16_t freq_now = cfg_tbl[CFG_OFS_FRE_RATE];
        uint16_t five_temp;
	uint16_t temp;         //需要写入芯片的数字量
	OS_ERR os_err;

	if(cfg_tbl[CFG_OFS_AO_SPEED_UP] != 0){ 	/*延时增加*/
		while(freq_value >= (freq_now + i*100)){
			cfg_tbl[CFG_OFS_FRE_RATE] = (freq_now + i*100);
			cfg_tbl_temp[CFG_OFS_FRE_RATE] = (freq_now + i*100);
			switch (cfg_tbl[CFG_OFS_CTL_TYPE]) {
				case 0:     //0~5V输出控制。
                                        five_temp = (cal_para[CAL_OFS_VOH_HI] + cal_para[CAL_OFS_VOH_LO]) / 2;
					temp = (((five_temp - cal_para[CAL_OFS_VOH_LO]) * (freq_now + i*100))/5000) + cal_para[CAL_OFS_VOH_LO];
					ad5620_data_send(&ad5620_para, temp);
                                        five_temp = (cal_para[CAL_OFS_VOB_LO] + cal_para[CAL_OFS_VOB_HI]) / 2;
					temp = cal_para[CAL_OFS_VOB_LO] - (((cal_para[CAL_OFS_VOB_LO] - five_temp) * (freq_now + i*100))/5000);
					mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
					break;
				case 1:     //0~10V输出控制。
					temp = (((cal_para[CAL_OFS_VOH_HI] - cal_para[CAL_OFS_VOH_LO]) * (freq_now + i*100))/5000) + cal_para[CAL_OFS_VOH_LO];
					ad5620_data_send(&ad5620_para, temp);
					temp = cal_para[CAL_OFS_VOB_LO] - (((cal_para[CAL_OFS_VOB_LO] - cal_para[CAL_OFS_VOB_HI]) * (freq_now + i*100))/5000);
					mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
					break;
				case 2:     //4~20mA输出控制。
					temp = (((cal_para[CAL_OFS_AOH_HI] - cal_para[CAL_OFS_AOH_LO]) * (freq_now + i*100))/5000) + cal_para[CAL_OFS_AOH_LO];
					ad5620_data_send(&ad5620_para, temp);
					temp = cal_para[CAL_OFS_AOB_LO] - (((cal_para[CAL_OFS_AOB_LO] - cal_para[CAL_OFS_AOB_HI]) * (freq_now + i*100))/5000);
					mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
					break;
				default:
					//                    return false;
					break;
			} /* -----  end switch  ----- */
			i++;
			OSTimeDly (cfg_tbl[CFG_OFS_AO_SPEED_UP], OS_OPT_TIME_DLY, &os_err);
		}

	}else{ 					/*直接增加*/
		cfg_tbl[CFG_OFS_FRE_RATE] = freq_value;
		cfg_tbl_temp[CFG_OFS_FRE_RATE] = freq_value;
		switch (cfg_tbl[CFG_OFS_CTL_TYPE]) {
			case 0:     //0~5V输出控制。
                                five_temp = (cal_para[CAL_OFS_VOH_HI] + cal_para[CAL_OFS_VOH_LO]) / 2;
				temp = (((five_temp - cal_para[CAL_OFS_VOH_LO]) * (freq_now - i*100))/5000) + cal_para[CAL_OFS_VOH_LO];
                                ad5620_data_send(&ad5620_para, temp);
                                five_temp = (cal_para[CAL_OFS_VOB_LO] + cal_para[CAL_OFS_VOB_HI]) / 2;
				temp = cal_para[CAL_OFS_VOB_LO] - (((cal_para[CAL_OFS_VOB_LO] - five_temp) * (freq_now - i*100))/5000);
				mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
				break;
			case 1:     //0~10V输出控制。
				temp = (((cal_para[CAL_OFS_VOH_HI] - cal_para[CAL_OFS_VOH_LO]) * freq_value)/5000) + cal_para[CAL_OFS_VOH_LO];
				ad5620_data_send(&ad5620_para, temp);
				temp = cal_para[CAL_OFS_VOB_LO] - (((cal_para[CAL_OFS_VOB_LO] - cal_para[CAL_OFS_VOB_HI]) * freq_value)/5000);
				mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
				break;
			case 2:     //4~20mA输出控制。
				temp = (((cal_para[CAL_OFS_AOH_HI] - cal_para[CAL_OFS_AOH_LO]) * freq_value)/5000) + cal_para[CAL_OFS_AOH_LO];
				ad5620_data_send(&ad5620_para, temp);
				temp = cal_para[CAL_OFS_AOB_LO] - (((cal_para[CAL_OFS_AOB_LO] - cal_para[CAL_OFS_AOB_HI]) * freq_value)/5000);
				mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
				break;
			default:
				//                    return false;
				break;
		} /* -----  end switch  ----- */
	}

	return ;
}		/* -----  end of function set_increase_freq  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  set_reduce_freq
 *  Description:  降低频率
 * =====================================================================================
 */
void set_reduce_freq(uint16_t freq_value){

	uint16_t i = 1;
	uint16_t freq_now = cfg_tbl[CFG_OFS_FRE_RATE];
	uint16_t temp;         //需要写入芯片的数字量
        uint16_t five_temp;
	OS_ERR os_err;

	if(cfg_tbl[CFG_OFS_AO_SHOW_DOWN] != 0){ /*延时降低*/ 
		while(freq_value <= (freq_now - i* 100)){
			cfg_tbl[CFG_OFS_FRE_RATE] = (freq_now - i*100);
			cfg_tbl_temp[CFG_OFS_FRE_RATE] = (freq_now - i*100);
			switch (cfg_tbl[CFG_OFS_CTL_TYPE]) {
				case 0:     //0~5V输出控制。
                                        five_temp = (cal_para[CAL_OFS_VOH_HI] + cal_para[CAL_OFS_VOH_LO]) / 2;
					temp = (((five_temp - cal_para[CAL_OFS_VOH_LO]) * (freq_now - i*100))/5000) + cal_para[CAL_OFS_VOH_LO];
					ad5620_data_send(&ad5620_para, temp);
                                        five_temp = (cal_para[CAL_OFS_VOB_LO] + cal_para[CAL_OFS_VOB_HI]) / 2;
					temp = cal_para[CAL_OFS_VOB_LO] - (((cal_para[CAL_OFS_VOB_LO] - five_temp) * (freq_now - i*100))/5000);
					mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
					break;
				case 1:     //0~10V输出控制。
					temp = (((cal_para[CAL_OFS_VOH_HI] - cal_para[CAL_OFS_VOH_LO]) * (freq_now - i*100))/5000) + cal_para[CAL_OFS_VOH_LO];
					ad5620_data_send(&ad5620_para, temp);
					temp = cal_para[CAL_OFS_VOB_LO] - (((cal_para[CAL_OFS_VOB_LO] - cal_para[CAL_OFS_VOB_HI]) * (freq_now - i*100))/5000);
					mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
					break;
				case 2:     //4~20mA输出控制。
					temp = (((cal_para[CAL_OFS_AOH_HI] - cal_para[CAL_OFS_AOH_LO]) * (freq_now - i*100))/5000) + cal_para[CAL_OFS_AOH_LO];
					ad5620_data_send(&ad5620_para, temp);
					temp = cal_para[CAL_OFS_AOB_LO] - (((cal_para[CAL_OFS_AOB_LO] - cal_para[CAL_OFS_AOB_HI]) * (freq_now - i*100))/5000);
					mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
					break;
				default:
					//                    return false;
					break;
			} /* -----  end switch  ----- */
			i++;
			OSTimeDly (cfg_tbl[CFG_OFS_AO_SHOW_DOWN], OS_OPT_TIME_DLY, &os_err);
		}

	}else{ 					/*直接降低*/ 
		cfg_tbl[CFG_OFS_FRE_RATE] = freq_value;
		cfg_tbl_temp[CFG_OFS_FRE_RATE] = freq_value;
		switch (cfg_tbl[CFG_OFS_CTL_TYPE]) {
			case 0:     //0~5V输出控制。
                                five_temp = (cal_para[CAL_OFS_VOH_HI] + cal_para[CAL_OFS_VOH_LO]) / 2;
				temp = (((five_temp - cal_para[CAL_OFS_VOH_LO]) * (freq_now - i*100))/5000) + cal_para[CAL_OFS_VOH_LO];
                                ad5620_data_send(&ad5620_para, temp);
                                five_temp = (cal_para[CAL_OFS_VOB_LO] + cal_para[CAL_OFS_VOB_HI]) / 2;
				temp = cal_para[CAL_OFS_VOB_LO] - (((cal_para[CAL_OFS_VOB_LO] - five_temp) * (freq_now - i*100))/5000);
				mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
				break;
			case 1:     //0~10V输出控制。
				temp = (((cal_para[CAL_OFS_VOH_HI] - cal_para[CAL_OFS_VOH_LO]) * freq_value)/5000) + cal_para[CAL_OFS_VOH_LO];
				ad5620_data_send(&ad5620_para, temp);
				temp = cal_para[CAL_OFS_VOB_LO] - (((cal_para[CAL_OFS_VOB_LO] - cal_para[CAL_OFS_VOB_HI]) * freq_value)/5000);
				mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
				break;
			case 2:     //4~20mA输出控制。
				temp = (((cal_para[CAL_OFS_AOH_HI] - cal_para[CAL_OFS_AOH_LO]) * freq_value)/5000) + cal_para[CAL_OFS_AOH_LO];
				ad5620_data_send(&ad5620_para, temp);
				temp = cal_para[CAL_OFS_AOB_LO] - (((cal_para[CAL_OFS_AOB_LO] - cal_para[CAL_OFS_AOB_HI]) * freq_value)/5000);
				mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
				break;
			default:
				//                    return false;
				break;
		} /* -----  end switch  ----- */
	}

	return ;
}		/* -----  end of function set_reduce_freq  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  remote_set_ao_value
 *  Description:  远程控制AO输出（改变频率）
 * =====================================================================================
 */
void remote_set_ao_value(uint16_t freq_value){

//	uint8_t i = 1;
	uint16_t freq_now = cfg_tbl[CFG_OFS_FRE_RATE];
//	uint16_t temp;         //需要写入芯片的数字量
//	OS_ERR os_err;

	if(freq_value == freq_now){ //所需要调整频率与当前运行频率相同，无需再次调整。 
		return;
	}

	if(freq_value > freq_now){ 	//增加运行频率 
		set_increase_freq(freq_value);
#if 0
		if(cfg_tbl[CFG_OFS_AO_SPEED_UP] != 0){
		while(freq_value >= (freq_now + i*100)){
			cfg_tbl[CFG_OFS_FRE_RATE] = (freq_now + i*100);
			cfg_tbl_temp[CFG_OFS_FRE_RATE] = (freq_now + i*100);
			switch (cfg_tbl[CFG_OFS_CTL_TYPE]) {
				case 0:     //0~5V输出控制。
					break;
				case 1:     //0~10V输出控制。
					break;
				case 2:     //4~20mA输出控制。
					temp = (((cal_para[CAL_OFS_AOH_HI] - cal_para[CAL_OFS_AOH_LO]) * (freq_now + i*100))/5000) + cal_para[CAL_OFS_AOH_LO];
					ad5620_data_send(&ad5620_para, temp);
					temp = cal_para[CAL_OFS_AOB_LO] - (((cal_para[CAL_OFS_AOB_LO] - cal_para[CAL_OFS_AOB_HI]) * (freq_now + i*100))/5000);
					mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
					break;
				default:
					//                    return false;
					break;
			} /* -----  end switch  ----- */
			i++;
			OSTimeDly (cfg_tbl[CFG_OFS_AO_SPEED_UP] * 10, OS_OPT_TIME_DLY, &os_err);
		}
		}
#endif
	}else{ 				//降低运行频率 
		set_reduce_freq(freq_value);
#if 0
		if(cfg_tbl[CFG_OFS_AO_SHOW_DOWN] != 0){
		while(freq_value <= (freq_now - i* 100)){
			cfg_tbl[CFG_OFS_FRE_RATE] = (freq_now - i*100);
			cfg_tbl_temp[CFG_OFS_FRE_RATE] = (freq_now - i*100);
			switch (cfg_tbl[CFG_OFS_CTL_TYPE]) {
				case 0:     //0~5V输出控制。
					break;
				case 1:     //0~10V输出控制。
					break;
				case 2:     //4~20mA输出控制。
					temp = (((cal_para[CAL_OFS_AOH_HI] - cal_para[CAL_OFS_AOH_LO]) * (freq_now - i*100))/5000) + cal_para[CAL_OFS_AOH_LO];
					ad5620_data_send(&ad5620_para, temp);
					temp = cal_para[CAL_OFS_AOB_LO] - (((cal_para[CAL_OFS_AOB_LO] - cal_para[CAL_OFS_AOB_HI]) * (freq_now - i*100))/5000);
					mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
					break;

				default:
					//                    return false;
					break;
			} /* -----  end switch  ----- */
			i++;
			OSTimeDly (cfg_tbl[CFG_OFS_AO_SHOW_DOWN] * 10, OS_OPT_TIME_DLY, &os_err);
		}
		}
#endif
	}

#if 0
	cfg_tbl[CFG_OFS_FRE_RATE] = freq_value;
	cfg_tbl_temp[CFG_OFS_FRE_RATE] = freq_value;
	switch (cfg_tbl[CFG_OFS_CTL_TYPE]) {
		case 0:     //0~5V输出控制。
			break;
		case 1:     //0~10V输出控制。
			break;
		case 2:     //4~20mA输出控制。
			temp = (((cal_para[CAL_OFS_AOH_HI] - cal_para[CAL_OFS_AOH_LO]) * freq_value)/5000) + cal_para[CAL_OFS_AOH_LO];
			ad5620_data_send(&ad5620_para, temp);
			temp = cal_para[CAL_OFS_AOB_LO] - (((cal_para[CAL_OFS_AOB_LO] - cal_para[CAL_OFS_AOB_HI]) * freq_value)/5000);
			mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
			break;
		default:
			//                    return false;
			break;
	} /* -----  end switch  ----- */
#endif
        save_cfg_para(0);   //只存储参数，不复位设备。

	return ;
}		/* -----  end of function remote_set_ao_value  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  reflash_set_ao_value
 *  Description:  本地刷新AO输出
 * =====================================================================================
 */
void reflash_set_ao_value(uint16_t value){

	uint16_t temp;
        uint16_t five_temp;

	if((value >= 0) && (value <= 5000)){
		switch (cfg_tbl[CFG_OFS_CTL_TYPE]) {
			case 0:     //0~5V输出控制。
                                five_temp = (cal_para[CAL_OFS_VOH_HI] + cal_para[CAL_OFS_VOH_LO]) / 2;
				temp = (((five_temp - cal_para[CAL_OFS_VOH_LO]) * value)/5000) + cal_para[CAL_OFS_VOH_LO];
				ad5620_data_send(&ad5620_para, temp);
                                five_temp = (cal_para[CAL_OFS_VOB_LO] + cal_para[CAL_OFS_VOB_HI]) / 2;
				temp = cal_para[CAL_OFS_VOB_LO] - (((cal_para[CAL_OFS_VOB_LO] - five_temp) * value)/5000);
				mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
				break;
			case 1:     //0~10V输出控制。
				temp = (((cal_para[CAL_OFS_VOH_HI] - cal_para[CAL_OFS_VOH_LO]) * value)/5000) + cal_para[CAL_OFS_VOH_LO];
//				PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
//				printf("temp1== [%d]\r\n", temp);
//				PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
				ad5620_data_send(&ad5620_para, temp);
				temp = cal_para[CAL_OFS_VOB_LO] - (((cal_para[CAL_OFS_VOB_LO] - cal_para[CAL_OFS_VOB_HI]) * value)/5000);
//				PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
//				printf("temp2== [%d]\r\n", temp);
//				PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
				mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
				break;
			case 2:     //4~20mA输出控制。
				temp = (((cal_para[CAL_OFS_AOH_HI] - cal_para[CAL_OFS_AOH_LO]) * value)/5000) + cal_para[CAL_OFS_AOH_LO];
				ad5620_data_send(&ad5620_para, temp);
				temp = cal_para[CAL_OFS_AOB_LO] - (((cal_para[CAL_OFS_AOB_LO] - cal_para[CAL_OFS_AOB_HI]) * value)/5000);
				mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
				break;
			default:
				//                    return false;
				break;
		} /* -----  end switch  ----- */
	}

	return ;
}		/* -----  end of function reflash_set_ao_value  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  set_vo5_value
 *  Description:  设置0-5V输出的控制方式值。
 * =====================================================================================
 */
void set_vo5_value(void){

	uint8_t ret;

	ret = OSAL_SEM_Pend(&freq_ctrl_sem, 10000);		/*等待接收的信号量*/
	if(ret == DEF_OK){        //接收到数据
                remote_set_ao_value(set_freq_value);
		
	}else{
//		reflash_set_ao_value(freq_value);
	}


	return ;
}		/* -----  end of function set_vo5_value  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  set_vo10_value
 *  Description:  设置0-10V输出的控制方式值。
 * =====================================================================================
 */
void set_vo10_value(void){

	uint8_t ret;

	ret = OSAL_SEM_Pend(&freq_ctrl_sem, 10000);		/*等待接收的信号量*/
	if(ret == DEF_OK){        //接收到数据
		remote_set_ao_value(set_freq_value);
	}else{
//		reflash_set_ao_value(freq_value);
	}

	return ;
}		/* -----  end of function set_vo10_value  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  set_ao_value
 *  Description:  控制AO输出
 * =====================================================================================
 */
void set_ao_value(void){

	uint8_t ret;
//	uint16_t freq_value = cfg_tbl[CFG_OFS_FRE_RATE];

	ret = OSAL_SEM_Pend(&freq_ctrl_sem, 10000);		/*等待接收的信号量*/
	if(ret == DEF_OK){        //接收到数据
                if(app4Data.state == APP_STATE_CALBRITION){
			return;
		}else{
			remote_set_ao_value(set_freq_value);
		}
	}else{
//		reflash_set_ao_value(freq_value);
	}

	return ;
}		/* -----  end of function set_ao_value  ----- */


/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  linear_relation_switch
 *  Description:  坐标轴线性关系变换函数,输入X参数，输出Y参数。
 * =====================================================================================
 */
int16_t linear_relation_switch(int16_t x_min, int16_t y_min, int16_t x_max, int16_t y_max, int16_t x_val){

	uint16_t temp = 0;
	OS_ERR os_err;
	
	if((x_max - x_min) == 0){
		return 0;
	}else{
		temp = ((y_max - y_min) * x_val + x_max*y_min - x_min*y_max)/(x_max - x_min);
//		PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
//		printf("(%d,%d)(%d,%d) == (%d,[%d])", x_min, y_min, x_max, y_max, x_val, temp);
//		OSTimeDly (1, OS_OPT_TIME_DLY, &os_err);
//		PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
		return temp;
	}
#if 0
	if((y_max - y_min) == 0){	//防止除数是0导致程序异常
		return 0;
	}
	temp = ((x_max - x_min) * y_val + x_min*y_max - x_max*y_min)/(y_max - y_min);
	PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
	printf("(%d,%d)(%d,%d) == ([%d],%d)", x_min, y_min, x_max, y_max, temp, y_val);
	OSTimeDly (1, OS_OPT_TIME_DLY, &os_err);
	PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
#endif
	return temp;    
}		/* -----  end of function linear_relation_switch  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  send_vo_value
 *  Description:  写入数字量改变VO的输出值。
 * =====================================================================================
 */
void send_vo_value(uint16_t value){

	uint16_t temp = 0;

	temp = linear_relation_switch(0, cal_para[CAL_OFS_VOH_LO], 6000, cal_para[CAL_OFS_VOH_HI], value);
	ad5620_data_send(&ad5620_para, temp);
//	mcp4161_data_send(&mcp4161_para, temp);       //对应中间值电压?V
	
	return ;
}		/* -----  end of function send_vo_value  ----- */


/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  motor_model1_count
 *  Description:  电机检测模式1计算函数，输入时间，计算出力矩。
 * =====================================================================================
 */
uint16_t motor_model1_count(uint16_t timer_count){

	if((timer_count >= 0) && (timer_count <= motor_timer1)){
		return 0;
	}
	if((timer_count > motor_timer1) && (timer_count <= motor_timer2)){
		return motor_moment1;
	}
	if((timer_count > motor_timer2) && (timer_count <= motor_timer3)){
		return motor_moment2;
	}
	if((timer_count > motor_timer3) && (timer_count <= motor_timer4)){
		return motor_moment3;
	}
	if((timer_count > motor_timer4) && (timer_count <= motor_timer5)){
		return motor_moment4;
	}
	if(timer_count >= motor_timer5){
		motor_test_count ++;
		if(motor_test_count >= motor_test_nb){
			motor_test_count = 0;
			moment_value = motor_moment5;
			app4Data.state = MODEL_IDLE;
			return motor_moment5;
		}else{
			timer_value = 0;
			moment_value = 0;
			return 0;
		}
	}
}		/* -----  end of function motor_model1_count  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  motor_model2_count
 *  Description:  电机检测模式2计算函数，输入时间，计算出力矩。
 * =====================================================================================
 */
uint16_t motor_model2_count(uint16_t timer_count){

	uint16_t temp = 0;

	if((timer_count >= 0) && (timer_count <= motor_timer1)){ /*线性增加*/ 
		temp = linear_relation_switch(0, 0, motor_timer1, motor_moment1, timer_count);
		return temp;
	}
	if((timer_count > motor_timer1) && (timer_count <= motor_timer2)){ /*恒定数值*/ 
		return motor_moment1;
	}
	if(timer_count > motor_timer2){ /*测试结束*/ 
		motor_test_count ++;
		if(motor_test_count >= motor_test_nb){
			motor_test_count = 0;
			app4Data.state = MODEL_IDLE;
			moment_value = motor_moment1;
			return motor_moment1;
		}else{
			timer_value = 0;
			moment_value = 0;
			return 0;
		}

	}
}		/* -----  end of function motor_model2_count  ----- */

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  motor_model3_count
 *  Description:  电机检测模式3计算函数，输入时间，计算出力矩。
 * =====================================================================================
 */
uint16_t motor_model3_count(uint16_t timer_count){

	uint16_t temp = 0;

	if((timer_count >= 0) && (timer_count <= motor_timer1)){ /*线性增加*/ 
		temp = linear_relation_switch(0, 0, motor_timer1, motor_moment1, timer_count);
		return temp;
	}

	if((timer_count > motor_timer1) && (timer_count <= motor_timer2)){ /*恒定数值*/ 
		return motor_moment1;
	}
	if((timer_count > motor_timer2) && (timer_count <= motor_timer3)){ /*线性减少*/ 
		temp = linear_relation_switch(motor_timer2, motor_moment1, motor_timer3, 0, timer_count);
		return temp;
	}

	if(timer_count >= motor_timer3){ /*测试结束*/ 
		motor_test_count ++;
		if(motor_test_count >= motor_test_nb){
			motor_test_count = 0;
			app4Data.state = MODEL_IDLE;
			moment_value = 0;
			return 0;
		}else{
			timer_value = 0;
			moment_value = 0;
			return 0;
		}
	}

	return ;
}		/* -----  end of function motor_model3_count  ----- */

/*******************************************************************************
  Function:
    void APP4_Initialize ( void )

  Remarks:
    See prototype in app4.h.
 */

void APP4_Initialize ( void )
{
    /* Place the App state machine in its initial state. */
    app4Data.state = APP4_STATE_INIT;

    /* TODO: Initialize your application's state machine and other
     * parameters.
     */

	ad5620_para.CS_HI = &ad5620_cs_hi;
	ad5620_para.CS_LO = &ad5620_cs_lo;

	ad5620_para.DO_HI = &ad5620_do_hi;
	ad5620_para.DO_LO = &ad5620_do_lo;

	ad5620_para.CK_HI = &ad5620_ck_hi;
	ad5620_para.CK_LO = &ad5620_ck_lo;


	mcp4161_para.CS_HI = &mcp4161_cs_hi;
	mcp4161_para.CS_LO = &mcp4161_cs_lo;

	mcp4161_para.DO_HI = &ad5620_do_hi;
	mcp4161_para.DO_LO = &ad5620_do_lo;

	mcp4161_para.CK_HI = &ad5620_ck_hi;
	mcp4161_para.CK_LO = &ad5620_ck_lo;

	load_motor_def_para();
       
}

//MCP4161对应值为0~255 。|| 5-0V。
//AD5620 对应值为0~4095。|| 0-2.5V。

/******************************************************************************
  Function:
    void APP4_Tasks ( void )

  Remarks:
    See prototype in app4.h.
 */

//主路
//输出公式：X = ((H - L) * Y)/5000 + L;
//X:DA输出数字量。H：校准上限值，L：校准下限值。Y：目标频率。
//
//备用
//输出公式：X = L - ((L - H) * Y)/5000;
//

void APP4_Tasks(void) {

        OS_ERR os_err;
	
	/* Check the application's current state. */
	switch (app4Data.state) {
		/* Application's initial state. */
		case APP4_STATE_INIT:
			{
				timer_value = 0;
				moment_value = 0;
				app4Data.state = MODEL_IDLE;
//				reflash_set_ao_value(cfg_tbl[CFG_OFS_FRE_RATE]); //周期性写入输出值。
//				set_ao_value(); //等待10S钟，接收到远端摸命令后写入。
				break;
			}
		case APP_STATE_CALBRITION: /*校准模式*/
			{
                                pcf8575_led_on(LED_LO_03);
				OSTimeDly (10000, OS_OPT_TIME_DLY, &os_err);
			}
			/* TODO: implement your application state machine.*/
		case MODEL_IDLE:			
			if(motor_idle_count >= 300){
				motor_idle_count = 0;
				send_vo_value(moment_value);
			}
			pcf8575_led_off(LED_HI_01);
			pcf8575_led_off(LED_HI_02);
			pcf8575_led_off(LED_HI_03);
			if (cfg_tbl[CFG_OFS_CAN_DEBUG_LEVEL] >= 2){
				PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
				printf("MODEL = [IDLE] | (x, y) = (%d,%d)\r\n", timer_value, moment_value);
				OSTimeDly (1, OS_OPT_TIME_DLY, &os_err);
				PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
			}
			motor_idle_count += 10;
			OSTimeDly (10, OS_OPT_TIME_DLY, &os_err);
			break;
		case MODEL_1:
			if (timer_value == 0) {
				pcf8575_led_on(LED_HI_01);
				pcf8575_led_off(LED_HI_02);
				pcf8575_led_off(LED_HI_03);
			}
			moment_value = motor_model1_count(timer_value);
			send_vo_value(moment_value);
			if (cfg_tbl[CFG_OFS_CAN_DEBUG_LEVEL] >= 2){
				PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
				printf("MODEL = [MOD1] | (x, y) = (%d,%d)\r\n", timer_value, moment_value);
				OSTimeDly (1, OS_OPT_TIME_DLY, &os_err);
				PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
			}
			timer_value += 20;
			OSTimeDly (20, OS_OPT_TIME_DLY, &os_err);
			break;
		case MODEL_2:
			if (timer_value == 0) {
				pcf8575_led_on(LED_HI_01);
				pcf8575_led_on(LED_HI_02);
				pcf8575_led_off(LED_HI_03);
			}

			moment_value = motor_model2_count(timer_value);
			send_vo_value(moment_value);
			if (cfg_tbl[CFG_OFS_CAN_DEBUG_LEVEL] >= 2){
				PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
				printf("MODEL = [MOD2] | (x, y) = (%d,%d)\r\n", timer_value, moment_value);
				OSTimeDly (1, OS_OPT_TIME_DLY, &os_err);
				PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
			}
			timer_value += 20;
			OSTimeDly (20, OS_OPT_TIME_DLY, &os_err);
			break;
		case MODEL_3:
			if(timer_value == 0) {
				pcf8575_led_on(LED_HI_01);
				pcf8575_led_on(LED_HI_02);
				pcf8575_led_on(LED_HI_03);
			}
			moment_value = motor_model3_count(timer_value);
			send_vo_value(moment_value);
			if (cfg_tbl[CFG_OFS_CAN_DEBUG_LEVEL] >= 2){
				PLIB_PORTS_PinSet(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
				printf("MODEL = [MOD3] | (x, y) = (%d,%d)\r\n", timer_value, moment_value);
				OSTimeDly (1, OS_OPT_TIME_DLY, &os_err);
				PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_F, PORTS_BIT_POS_3);
			}
			timer_value += 20;
			OSTimeDly (20, OS_OPT_TIME_DLY, &os_err);
			break;
		case MODEL_4:
			break;
			/* The default state should never be executed. */
		default:
			{
				/* TODO: Handle error in application's state machine. */
				break;
			}
	}
}


/*******************************************************************************
 End of File
 */
